package buildings.office;

import buildings.iterators.OfficeFloorIterator;
import buildings.exceptions.SpaceIndexOutOfBoundsException;
import buildings.Floor;
import buildings.Space;
import buildings.dwelling.DwellingFloor;
import java.io.Serializable;
import java.util.Iterator;

public class OfficeFloor implements Floor, Serializable, Cloneable {

    private OfficeNode head;
    private OfficeNode current;
    private int count;

    private OfficeNode getOfficeNodeByNumber(int number) {
        if (number >= count) {
            throw new SpaceIndexOutOfBoundsException();
        }
        current = head;
        int i = 0;
        while (i != number) {
            current = current.getNext();
            i++;
        }
        return current;
    }

    private void addOfficeNodeByNumber(OfficeNode office, int number) {
        if (number > count) {
            throw new SpaceIndexOutOfBoundsException();
        }
        if(count == 0) {
            head = office;
            head.setNext(head);
            count++;
            return;
        }
        if (number == 0) {
            current = head;
            int i = 0;
            while (i != count - 1) {
                current = current.getNext();
                i++;
            }
            office.setNext(head);
            current.setNext(office);
            head = office;
        } else {
            current = head;
            int i = 0;
            while (i != number - 1) {
                current = current.getNext();
                i++;
            }
            office.setNext(current.getNext());
            current.setNext(office);
        }
        count++;
    }

    private void deleteOfficeNodeByNumber(int number) {
        if (number > count) {
            throw new SpaceIndexOutOfBoundsException();
        }
        if (number == 0) {
            current = head;
            int i = 0;
            while (i != count - 1) {
                current = current.getNext();
                i++;
            }
            head = head.getNext();
            current.setNext(head);
        } else {
            current = head;
            OfficeNode deleting;
            int i = 0;
            while (i != number - 1) {
                current = current.getNext();
                i++;
            }
            deleting = current.getNext();
            current.setNext(deleting.getNext());
        }
        count--;
    }

    public OfficeFloor(int count) {
        if (count < 0) {
            throw new SpaceIndexOutOfBoundsException();
        }
        if (count == 0) {
            head = null;
            this.count = 0;
            return;
        }
        head = new OfficeNode();
        head.setNext(head);             //замыкание списка
        current = head;
        this.count = 1;
        for (int i = 1; i < count; i++, this.count++) {
            current.setNext(new OfficeNode());
            if (i == count - 1) {
                current.getNext().setNext(head);
            } else {
                current = current.getNext();
            }
        }
    }

    public OfficeFloor(Space[] offices) {
        if (offices.length < 1) {
            throw new SpaceIndexOutOfBoundsException();
        }
        head = new OfficeNode(offices[0]);
        head.setNext(head);
        current = head;
        this.count = 1;
        for (int i = 1; i < offices.length; i++, count++) {
            current.setNext(new OfficeNode(offices[i]));
            if (i == offices.length - 1) {
                current.getNext().setNext(head);
            } else {
                current = current.getNext();
            }
        }
    }

    public int getSpaceCount() {
        return count;
    }

    public float getTotalSquare() {
        float totalSquare = 0;
        current = head;
        for (int i = 0; i < count; i++) {
            totalSquare += current.getElement().getSquare();
            current = current.getNext();
        }
        return totalSquare;
    }

    public int getTotalRoomCount() {
        int roomCount = 0;
        current = head;
        for (int i = 0; i < count; i++) {
            roomCount += current.getElement().getRoomCount();
            current = current.getNext();
        }
        return roomCount;
    }

    public Space[] getSpaces() {
        Space offices[] = new Office[count];
        current = head;
        for (int i = 0; i < count; i++) {
            offices[i] = current.getElement();
            current = current.getNext();
        }
        return offices;
    }

    public Space getSpaceByNumber(int number) {
        return getOfficeNodeByNumber(number).getElement();
    }

    public void addSpaceByNumber(int number, Space office) {
        addOfficeNodeByNumber(new OfficeNode(office), number);
    }

    public void setSpaceByNumber(int number, Space office) {
        getOfficeNodeByNumber(number).setElement(office);
    }

    public void deleteSpaceByNumber(int number) {
        deleteOfficeNodeByNumber(number);
    }

    public Space getBestSpace() {
        Space bestFlat = head.getElement();
        current = head;
        float bestSquare = 0;
        for (int i = 0; i < count; i++) {
            if (bestSquare < current.getElement().getSquare()) {
                bestSquare = current.getElement().getSquare();
                bestFlat = current.getElement();
            }
        }
        return bestFlat;
    }

    public Iterator iterator() {
        return new Iterator() {
            private int count = 0;

            public Space next() {
                return getSpaceByNumber(count++);
            }

            public boolean hasNext() {
                return getSpaceCount() < count;
            }

            public void remove() throws UnsupportedOperationException {
                throw new UnsupportedOperationException();
            }
        };
    }

    public String toString() {
        StringBuffer buf = new StringBuffer(this.getClass().getSimpleName()
                + " (" + count + ",");
        current = head;
        for (int i = 0; i < count; i++) {
            buf.append(" ");
            buf.append(current.getElement());
            current = current.getNext();
        }
        buf.append(")");
        return buf.toString();
    }

    public boolean equals(Object obj) {
        if(!(obj instanceof OfficeFloor))
            return false;
        boolean isSpacesEquals = true;
        current = head;
        for (int i = 0; i < count; i++) {
            if (!((OfficeFloor) obj).getSpaceByNumber(i).equals(current.getElement())) {
                isSpacesEquals = false;
                break;
            }
            current = current.getNext();
        }
        return ((((OfficeFloor) obj).getSpaceCount() == count)
                && (isSpacesEquals));
    }
    
    public int hashCode() {
        int hash = count;
        for(int i = 0; i < count; i++) {
            hash |= getSpaceByNumber(i).hashCode();
        }
        return hash;
    }
    
    public Object clone() throws CloneNotSupportedException {
        Object result = super.clone();
        ((OfficeFloor)result).head = (OfficeNode)head.clone();
        ((OfficeFloor)result).current = (OfficeNode)current.clone();
        return result;
    }
}
